package com.hymjweb.demo.config.beetl;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.util.Map;

/**
 * @BelongsProject: demo
 * @BelongsPackage: com.hymjweb.demo.config.beetl
 * @Author: luoge
 * @CreateTime: 2021-03-24 11:03
 * @Description:
 */
public class ShiroExt {

    protected Subject getSubject() {
        return SecurityUtils.getSubject();
    }

    /**
     *  the guest tag
     * @return
     */
    public boolean isGuest(){
        return getSubject() == null || getSubject().getPrincipal() == null;
    }

    /**
     * the user tag
     * @return
     */
    public boolean isUser(){
        return getSubject() != null && getSubject().getPrincipal() != null;
    }

    /**
     * the authenticated tag
     * @return
     */
    public boolean isAuthenticated(){
        return getSubject() != null && getSubject().isAuthenticated();
    }

    public boolean isNotAuthenticated(){
        return !isAuthenticated();
    }

    public String principal(Map map){
        String strValue = null;
        if(getSubject() != null){
            Object principal;
            String type = map != null ?(String)map.get("type"):null;
            if(type == null){
                principal = getSubject().getPrincipal();
            }
            else{
                principal = getPrincipalFromClassName(type);
            }

            String property = map != null ? (String)map.get("property"):null;
            if(principal!=null){
                if(property==null){
                    strValue = principal.toString();
                }
                else{
                    strValue = getPincipalProperty(principal,property);
                }
            }
        }

        if(strValue!=null){
            return strValue;
        }
        return null;
    }


    public boolean hasRole(String roleName){
        return getSubject()!=null && getSubject().hasRole(roleName);
    }

    public boolean lacksRole(String roleName){
        return !hasRole(roleName);
    }

    public boolean hasAnyRole(String roleNames){
        boolean hasAnyRole = false;
        Subject subject = getSubject();
        if(subject!=null){
            for(String roleName : roleNames.split(",")){
                if(subject.hasRole(roleName.trim())){
                    hasAnyRole = true;
                    break;
                }
            }
        }
        return hasAnyRole;
    }


    public boolean hasPermission(String p){
        return getSubject()!=null && getSubject().isPermitted(p);
    }

    public boolean lacksPermission(String p){
        return !hasPermission(p);
    }

    private Object getPrincipalFromClassName(String type){
        Object principal = null;
        try {

            Class cls = Class.forName(type);
            principal = getSubject().getPrincipals().oneByType(cls);

        }catch (ClassNotFoundException e){

        }
        return principal;
    }

    private String getPincipalProperty(Object principal,String property){
        String strValue = null;
        try{
            BeanInfo beanInfo = Introspector.getBeanInfo(principal.getClass());
            boolean foundProperty = false;
            for(PropertyDescriptor pd : beanInfo.getPropertyDescriptors()){
                if(pd.getName().equals(property)){
                    Object value =pd.getReadMethod().invoke(principal,(Object[])null);
                    strValue = String.valueOf(value);
                    foundProperty = true;
                    break;
                }
            }

            if(!foundProperty){
                final String message = "Property [" + property
                        + "] not found in principal of type ["
                        + principal.getClass().getName() + "]";

                throw new RuntimeException(message);
            }

        }
        catch (Exception e){
            final String message = "Error reading property [" + property
                    + "] from principal of type ["
                    + principal.getClass().getName() + "]";

            throw new RuntimeException(message, e);
        }
        return strValue;
    }




}
